package com.app.util.pool;

@SuppressWarnings("unchecked")
public final class ObjectPool<T> {

	private Object[] items;
	private boolean[] itemsFree;
	private long[] releaseTimes;
	private boolean closed = false;

	private PoolConfig<T> config;

	private final Object lock = new Object();

	public ObjectPool(PoolConfig<T> config) throws NewObjectException {
		this.config = config.clone();
		this.items = new Object[config.getMaxActive()];
		this.itemsFree = new boolean[config.getMaxActive()];
		this.releaseTimes = new long[config.getMaxActive()];
		init();
	}

	private void init() throws NewObjectException {
		for (int i = 0; i < config.getMaxActive(); i++) {
			releaseTimes[i] = System.currentTimeMillis();
			if (i == 0) {
				items[i] = config.getNewObjectHandler().newObject();
			}
			itemsFree[i] = true;
		}

		/** 维护线程 */
		Thread t = new Thread() {
			public void run() {
				while (!closed) {
					try {
						Thread.sleep(config.getCheckTimes() * 1000);
					} catch (InterruptedException e1) {
					}
					synchronized (lock) {
						for (int i = 0; i < itemsFree.length; i++) {
							if (itemsFree[i] && items[i] != null && System.currentTimeMillis() - releaseTimes[i] > config.getMaxIdle() * 1000) {
								close((T) items[i]);
								items[i] = null;
							}
						}
					}
				}
			}
		};

		t.setDaemon(true);
		t.start();
	}

	public T getObject() throws NewObjectException {
		if (closed) {
			throw new ObjectPoolException("Object pool had be closed.");
		}
		while (true) {
			synchronized (lock) {
				for (int i = 0; i < itemsFree.length; i++) {
					if (itemsFree[i]) {
						if (null == items[i]) {
							items[i] = config.getNewObjectHandler().newObject();
							itemsFree[i] = false;
						}
						return (T) items[i];
					}
				}
			}
		}
	}

	public void distoryObject(T object) {
		synchronized (lock) {
			for (int i = 0; i < itemsFree.length; i++) {
				if (items[i] == object) {
					close((T) items[i]);
					itemsFree[i] = true;
					items[i] = null;
					releaseTimes[i] = System.currentTimeMillis();
					break;
				}
			}
		}
	}

	public void releaseObject(T object) {
		synchronized (lock) {
			for (int i = 0; i < itemsFree.length; i++) {
				if (items[i] == object) {
					releaseTimes[i] = System.currentTimeMillis();
					itemsFree[i] = true;
					break;
				}
			}
		}
	}

	public void close() {
		while (true) {
			synchronized (lock) {
				for (int i = 0; i < itemsFree.length; i++) {
					if (itemsFree[i]) {
						if (items[i] != null) {
							close((T) items[i]);
							items[i] = null;
						}
						itemsFree[i] = false;
					}
				}
				break;
			}
		}
		closed = true;
	}

	private void close(T t) {
		try {
			config.getCloseObjectHandler().closeObject(t);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public boolean isClosed() {
		return closed;
	}

	public PoolConfig<T> getConfig() {
		return config;
	}
}
